/*-------------------------------------------------------------------------
 *
 * nodeAgg.h
 *	  nodeAgg.c的原型
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/executor/nodeAgg.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef NODEAGG_H
#define NODEAGG_H

#include "access/parallel.h"
#include "nodes/execnodes.h"


/*
 * AggStatePerTransData - 每个聚合状态值的信息
 *
 * 通过调用输入行的过渡函数来更新聚合的状态值的工作状态。此结构不存储
 * 从过渡状态生成最终聚合结果所需的信息，这些信息存储在AggStatePerAggData中。此分离
 * 允许从单个状态值生成多个聚合结果。
 */
typedef struct AggStatePerTransData
{
	/*
	 * 这些值在ExecInitAgg()期间设置，并在此后不再更改：
	 */

	/*
	 * 链接到此状态值对应的Aggref表达式。
	 *
	 * 只要输入和过渡函数相同且最终函数不是读写的，就可以有多个Aggref共享相同的状态值。
	 * 这指向其中的第一个。
	 */
	Aggref	   *aggref;

	/*
	 * 此状态值是否实际上被多个Aggref共享？
	 */
	bool		aggshared;

	/*
	 * 聚合输入列的数量。包括普通聚合和排序集合案例中的ORDER BY表达式。
	 * 不过，排序集合的直接参数不计算在内。
	 */
	int			numInputs;

	/*
	 * 要传递给transfn的聚合输入列的数量。包括排序集合聚合的ORDER BY列，但不包括普通聚合。
	 * （这不计算过渡状态值！）
	 */
	int			numTransInputs;

	/* 状态过渡或合并函数的Oid */
	Oid			transfn_oid;

	/* 序列化函数的Oid或InvalidOid */
	Oid			serialfn_oid;

	/* 反序列化函数的 Oid 或 InvalidOid */
	Oid			deserialfn_oid;

	/* 状态值的数据类型的 Oid */
	Oid			aggtranstype;

	/*
	 * 过渡函数或组合函数的 fmgr 查找数据。特别注意这里保存了
	 * fn_strict 标志。
	 */
	FmgrInfo	transfn;

	/* 序列化函数的 fmgr 查找数据 */
	FmgrInfo	serialfn;

	/* 反序列化函数的 fmgr 查找数据 */
	FmgrInfo	deserialfn;

	/* 为聚合派生的输入排序规则 */
	Oid			aggCollation;

	/* 排序列的数量 */
	int			numSortCols;

	/* 在 DISTINCT 比较中考虑的排序列的数量 */
	/* （这要么是零，要么与 numSortCols 相同） */
	int			numDistinctCols;

	/* 解构的排序信息（长度为 numSortCols 的数组） */
	AttrNumber *sortColIdx;
	Oid		   *sortOperators;
	Oid		   *sortCollations;
	bool	   *sortNullsFirst;

	/*
	 * 输入列的比较器 --- 仅在聚合具有 DISTINCT 标志时设置/使用。
	 * equalfnOne 版本用于单列比较，equalfnMulti 用于多列
	 * 比较。
	 */
	FmgrInfo	equalfnOne;
	ExprState  *equalfnMulti;

	/*
	 * 来自 pg_aggregate 条目的初始值
	 */
	Datum		initValue;
	bool		initValueIsNull;

	/*
	 * 我们需要 agg 的输入和过渡数据类型的 len 和 byval 信息，
	 * 以便知道如何复制/删除值。
	 *
	 * 注意，输入类型的信息仅在处理仅有一个参数的 DISTINCT 聚合时使用，
	 * 因此只有一个输入类型。
	 */
	int16		inputtypeLen,
				transtypeLen;
	bool		inputtypeByVal,
				transtypeByVal;

	/*
	 * 用于持有评估输入参数的槽。这些在 ExecInitAgg() 期间设置，
	 * 然后用于每个需要 FILTER 或 ORDER BY/DISTINCT 处理的输入行。
	 */
	TupleTableSlot *sortslot;	/* 当前输入元组 */
	TupleTableSlot *uniqslot;	/* 用于多列 DISTINCT */
	TupleDesc	sortdesc;		/* 输入元组的描述符 */

	/*
	 * 这些值是工作状态，在输入元组组开始时初始化，并为每个输入元组更新。
	 *
	 * 对于简单（非 DISTINCT/ORDER BY）聚合，我们只需将输入
	 * 值直接传递到过渡函数。如果是 DISTINCT 或
	 * 需要 ORDER BY，则我们将输入值传递到 Tuplesort 对象中；
	 * 然后在输入元组组完成时，我们扫描排序后的值，
	 * 如有必要消除重复，并在其余部分上运行过渡函数。
	 *
	 * 每个分组集都需要一个单独的 tuplesort。
	 */

	Tuplesortstate **sortstates;	/* 排序对象，如果是 DISTINCT 或 ORDER BY */

	/*
	 * 该字段是一个预初始化的 FunctionCallInfo 结构，用于
	 * 调用此聚合的 transfn。通过不重新初始化不变字段，我们为每行节省了几个周期；
	 * 这并不多，但似乎值得额外的空间消耗。
	 */
	FunctionCallInfo transfn_fcinfo;

	/* 序列化和反序列化函数同样适用 */
	FunctionCallInfo serialfn_fcinfo;

	FunctionCallInfo deserialfn_fcinfo;
}			AggStatePerTransData;

/*
 * AggStatePerAggData - 每个聚合的信息
 *
 * 这包含调用最终函数所需的信息，以从状态值生成最终的聚合结果。
 * 如果查询中有多个相同的 Aggrefs，则它们可以共享相同的每个聚合数据。
 *
 * 这些值在 ExecInitAgg() 过程中设置，此后不会改变。
 */
typedef struct AggStatePerAggData
{
	/*
	 * 链接到该状态值所对应的 Aggref 表达式。
	 *
	 * 可以有多个相同的 Aggref 共享相同的每个聚合数据。这
	 * 指向它们中的第一个。
	 */
	Aggref	   *aggref;

	/* 该聚合应使用的状态值索引 */
	int			transno;

	/* 最终函数的可选 Oid（可能是 InvalidOid） */
	Oid			finalfn_oid;

	/*
	 * 最终函数的 fmgr 查找数据 --- 仅在 finalfn_oid
	 * 不为 InvalidOid 时有效。
	 */
	FmgrInfo	finalfn;

	/*
	 * 传递给 finalfn 的参数数量。这个数量始终至少为 1
	 * （过渡状态值）加上任何有序集直接参数。如果 finalfn 需要额外的参数，
	 * 那么我们将对应于聚合输入列的 null 传递。
	 */
	int			numFinalArgs;

	/* 任意直接参数表达式的 ExprStates */
	List	   *aggdirectargs;

	/*
	 * 我们需要 agg 的结果数据类型的 len 和 byval 信息，
	 * 以便知道如何复制/删除值。
	 */
	int16		resulttypeLen;
	bool		resulttypeByVal;

	/*
	 * "shareable" 如果此聚合不能与其他聚合共享状态值，
	 * 则为 false，因为最终函数是读写的。
	 */
	bool		shareable;
}			AggStatePerAggData;

/*
 * AggStatePerGroupData - 每个聚合-每组的工作状态
 *
 * 这些值是工作状态，在输入元组组开始时初始化，并为每个输入元组更新。
 *
 * 在 AGG_PLAIN 和 AGG_SORTED 模式下，我们有一个这些
 * 结构的单一数组（由 aggstate->pergroup 指向）；如果是 AGG_SORTED 模式，
 * 我们将为每个输入组重新使用该数组。在 AGG_HASHED 模式下，
 * 哈希表为每个元组组包含一个这些结构的数组。
 *
 * 从逻辑上讲，sortstate 字段属于该结构，但由于空间原因，
 * 我们不在这里保留它：我们在 AGG_HASHED 模式下不支持 DISTINCT 聚合，
 * 因此没有理由在哈希表的每一条目中使用指针字段。
 */
typedef struct AggStatePerGroupData
{
#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUE 0
	Datum		transValue;		/* 当前过渡值 */
#define FIELDNO_AGGSTATEPERGROUPDATA_TRANSVALUEISNULL 1
	bool		transValueIsNull;

#define FIELDNO_AGGSTATEPERGROUPDATA_NOTRANSVALUE 2
	bool		noTransValue;	/* 如果 transValue 尚未设置，则为 true */

	/*
	 * 注意：noTransValue最初与transValueIsNull具有相同的值，
	 * 如果为真，则同时将两者清除为假。它们并不相同：如果transfn后来返回NULL，
	 * 我们想保留那个NULL，而不是用后续的输入值自动替换它。只有第一个非NULL输入会被自动替换。
	 */
}			AggStatePerGroupData;

/*
 * AggStatePerPhaseData - 每个分组集阶段的状态
 *
 * 分组集被划分为“阶段”，在单个阶段中可以对输入进行一次处理。
 * 如果有多个阶段，则在当前阶段输入结束时，状态会重置，并对在此期间重新排序过的数据进行再次处理。
 *
 * 因此，每个阶段指定一列分组集和组子句信息，除第一阶段外，每个阶段还具有一种排序顺序。
 */
typedef struct AggStatePerPhaseData
{
	AggStrategy aggstrategy;	/* 该阶段的策略 */
	int			numsets;		/* 分组集的数量（或0） */
	int		   *gset_lengths;	/* 分组集的长度 */
	Bitmapset **grouped_cols;	/* 用于汇总的列分组 */
	ExprState **eqfunctions;	/* 返回相等的表达式，以比较列数为索引 */
	Agg		   *aggnode;		/* 阶段数据的Agg节点 */
	Sort	   *sortnode;		/* 用于阶段的输入排序的排序节点 */

	ExprState  *evaltrans;		/* 过渡函数的评估  */

	/*----------
	 * 编译表达式的缓存变体。
	 * 第一个下标：0：outerops；1：TTSOpsMinimalTuple
	 * 第二个下标：0：无NULL检查；1：有NULL检查
	 *----------
	 */
	ExprState  *evaltrans_cache[2][2];
}			AggStatePerPhaseData;

/*
 * AggStatePerHashData - 每个哈希表的状态
 *
 * 当使用哈希进行分组集时，我们为每个分组集有一个这样的结构。
 * （当进行无分组集的哈希时，我们只需一个。）
 */
typedef struct AggStatePerHashData
{
	TupleHashTable hashtable;	/* 每个组一个条目的哈希表 */
	TupleHashIterator hashiter; /* 遍历哈希表用 */
	TupleTableSlot *hashslot;	/* 用于加载哈希表的插槽 */
	FmgrInfo   *hashfunctions;	/* 每个分组字段的哈希函数 */
	Oid		   *eqfuncoids;		/* 每个分组字段的相等函数 */
	int			numCols;		/* 哈希键列的数量 */
	int			numhashGrpCols; /* 哈希表中列的数量 */
	int			largestGrpColIdx;	/* 哈希所需的最大列 */
	AttrNumber *hashGrpColIdxInput; /* 输入插槽中的哈希列索引 */
	AttrNumber *hashGrpColIdxHash;	/* 哈希表元组中的索引 */
	Agg		   *aggnode;		/* 原始Agg节点，用于numGroups等。 */
}			AggStatePerHashData;


extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags);
extern void ExecEndAgg(AggState *node);
extern void ExecReScanAgg(AggState *node);

extern Size hash_agg_entry_size(int numTrans, Size tupleWidth,
								Size transitionSpace);
extern void hash_agg_set_limits(double hashentrysize, double input_groups,
								int used_bits, Size *mem_limit,
								uint64 *ngroups_limit, int *num_partitions);

/* 并行仪表支持 */
extern void ExecAggEstimate(AggState *node, ParallelContext *pcxt);
extern void ExecAggInitializeDSM(AggState *node, ParallelContext *pcxt);
extern void ExecAggInitializeWorker(AggState *node, ParallelWorkerContext *pwcxt);
extern void ExecAggRetrieveInstrumentation(AggState *node);

#endif							/* NODEAGG_H */
